home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / afxtls.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  12.8 KB  |  512 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #ifndef _INC_STDDEF
  13. #include <stddef.h>
  14. #endif
  15.  
  16. #ifdef AFX_INIT_SEG
  17. #pragma code_seg(AFX_INIT_SEG)
  18. #endif
  19.  
  20. #ifdef _DEBUG
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CSimpleList
  27.  
  28. void CSimpleList::AddHead(void* p)
  29. {
  30.     ASSERT(p != NULL);
  31.     ASSERT(*GetNextPtr(p) == NULL);
  32.  
  33.     *GetNextPtr(p) = m_pHead;
  34.     m_pHead = p;
  35. }
  36.  
  37. BOOL CSimpleList::Remove(void* p)
  38. {
  39.     ASSERT(p != NULL);
  40.  
  41.     if (m_pHead == NULL)
  42.         return FALSE;
  43.  
  44.     BOOL bResult = FALSE;
  45.     if (m_pHead == p)
  46.     {
  47.         m_pHead = *GetNextPtr(p);
  48.         DEBUG_ONLY(*GetNextPtr(p) = NULL);
  49.         bResult = TRUE;
  50.     }
  51.     else
  52.     {
  53.         void* pTest = m_pHead;
  54.         while (pTest != NULL && *GetNextPtr(pTest) != p)
  55.             pTest = *GetNextPtr(pTest);
  56.         if (pTest != NULL)
  57.         {
  58.             *GetNextPtr(pTest) = *GetNextPtr(p);
  59.             DEBUG_ONLY(*GetNextPtr(p) = NULL);
  60.             bResult = TRUE;
  61.         }
  62.     }
  63.     return bResult;
  64. }
  65.  
  66. /////////////////////////////////////////////////////////////////////////////
  67. // CNoTrackObject
  68.  
  69. #if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
  70. void* PASCAL CNoTrackObject::operator new(size_t nSize, LPCSTR, int)
  71. {
  72.     return CNoTrackObject::operator new(nSize);
  73. }
  74.  
  75. #if _MSC_VER >= 1200
  76. void PASCAL CNoTrackObject::operator delete(void* pObject, LPCSTR, int)
  77. {
  78.     if (pObject != NULL)
  79.         ::LocalFree(pObject);
  80. }
  81. #endif
  82. #endif
  83.  
  84. void* PASCAL CNoTrackObject::operator new(size_t nSize)
  85. {
  86.     void* p = ::LocalAlloc(LPTR, nSize);
  87.     if (p == NULL)
  88.         AfxThrowMemoryException();
  89.     return p;
  90. }
  91.  
  92. void PASCAL CNoTrackObject::operator delete(void* p)
  93. {
  94.     if (p != NULL)
  95.         ::LocalFree(p);
  96. }
  97.  
  98. /////////////////////////////////////////////////////////////////////////////
  99. // CThreadSlotData
  100.  
  101. // global _afxThreadData used to allocate thread local indexes
  102. BYTE __afxThreadData[sizeof(CThreadSlotData)];
  103. CThreadSlotData* _afxThreadData;
  104.  
  105. struct CThreadData : public CNoTrackObject
  106. {
  107.     CThreadData* pNext; // required to be member of CSimpleList
  108.     int nCount;         // current size of pData
  109.     LPVOID* pData;      // actual thread local data (indexed by nSlot)
  110. };
  111.  
  112. struct CSlotData
  113. {
  114.     DWORD dwFlags;      // slot flags (allocated/not allocated)
  115.     HINSTANCE hInst;    // module which owns this slot
  116. };
  117.  
  118. // flags used for CSlotData::dwFlags above
  119. #define SLOT_USED   0x01    // slot is allocated
  120.  
  121. #if defined(_WIN32_WCE)
  122. CThreadSlotData::CThreadSlotData()
  123. #else // _WIN32_WCE
  124. __declspec(nothrow) CThreadSlotData::CThreadSlotData()
  125. #endif // _WIN32_WCE
  126. {
  127.     m_list.Construct(offsetof(CThreadData, pNext));
  128.  
  129.     // initialize state and allocate TLS index
  130.     m_nAlloc = 0;
  131.     m_nRover = 1;   // first slot (0) is always reserved
  132.     m_nMax = 0;
  133.     m_pSlotData = NULL;
  134.  
  135.     // init m_tlsIndex to -1 if !bThreadLocal, otherwise TlsAlloc
  136.     m_tlsIndex = TlsAlloc();
  137.     if (m_tlsIndex == (DWORD)-1)
  138.         AfxThrowMemoryException();
  139.  
  140.     InitializeCriticalSection(&m_sect);
  141. }
  142.  
  143. CThreadSlotData::~CThreadSlotData()
  144. {
  145.     if (m_tlsIndex != (DWORD)-1)
  146.     {
  147.         TlsFree(m_tlsIndex);
  148.         DEBUG_ONLY(m_tlsIndex = (DWORD)-1);
  149.     }
  150.  
  151.     CThreadData* pData = m_list;
  152.     while (pData != NULL)
  153.     {
  154.         CThreadData* pDataNext = pData->pNext;
  155.         DeleteValues(pData, NULL);
  156.         pData = pDataNext;
  157.     }
  158.  
  159.     if (m_pSlotData != NULL)
  160.     {
  161.         HGLOBAL hSlotData = WCE_FCTN(GlobalHandle)(m_pSlotData);
  162.         WCE_FCTN(GlobalUnlock)(hSlotData);
  163.         WCE_FCTN(GlobalFree)(hSlotData);
  164.         DEBUG_ONLY(m_pSlotData = NULL);
  165.     }
  166.  
  167.     DeleteCriticalSection(&m_sect);
  168. }
  169.  
  170. int CThreadSlotData::AllocSlot()
  171. {
  172.     EnterCriticalSection(&m_sect);
  173.     int nAlloc = m_nAlloc;
  174.     int nSlot = m_nRover;
  175.     if (nSlot >= nAlloc || (m_pSlotData[nSlot].dwFlags & SLOT_USED))
  176.     {
  177.         // search for first free slot, starting at beginning
  178.         for (nSlot = 1;
  179.             nSlot < nAlloc && (m_pSlotData[nSlot].dwFlags & SLOT_USED); nSlot++)
  180.             ;
  181.  
  182.         // if none found, need to allocate more space
  183.         if (nSlot >= nAlloc)
  184.         {
  185.             // realloc memory for the bit array and the slot memory
  186.             int nNewAlloc = m_nAlloc+32;
  187.  
  188.             // m_pSlotData is allocated GMEM_SHARE because on Win32s it needs
  189.             // to be shared between processes (memory is owned by the MFC DLL).
  190.             HGLOBAL hSlotData;
  191.             if (m_pSlotData == NULL)
  192.             {
  193.                 hSlotData = WCE_FCTN(GlobalAlloc)(GMEM_MOVEABLE|GMEM_SHARE,
  194.                     nNewAlloc*sizeof(CSlotData));
  195.             }
  196.             else
  197.             {
  198.                 hSlotData = WCE_FCTN(GlobalHandle)(m_pSlotData);
  199.                 WCE_FCTN(GlobalUnlock)(hSlotData);
  200.                 hSlotData = WCE_FCTN(GlobalReAlloc)(hSlotData, nNewAlloc*sizeof(CSlotData),
  201.                     GMEM_MOVEABLE|GMEM_SHARE);
  202.             }
  203.             if (hSlotData == NULL)
  204.             {
  205.                 WCE_FCTN(GlobalLock)(WCE_FCTN(GlobalHandle)(m_pSlotData));
  206.                 LeaveCriticalSection(&m_sect);
  207.                 AfxThrowMemoryException();
  208.             }
  209.             CSlotData* pSlotData = (CSlotData*)WCE_FCTN(GlobalLock)(hSlotData);
  210.  
  211.             // always zero initialize after success
  212.             memset(pSlotData+m_nAlloc, 0, (nNewAlloc-m_nAlloc)*sizeof(CSlotData));
  213.             m_nAlloc = nNewAlloc;
  214.             m_pSlotData = pSlotData;
  215.         }
  216.     }
  217.     ASSERT(nSlot != 0); // first slot (0) is reserved
  218.  
  219.     // adjust m_nMax to largest slot ever allocated
  220.     if (nSlot >= m_nMax)
  221.         m_nMax = nSlot+1;
  222.  
  223.     ASSERT(!(m_pSlotData[nSlot].dwFlags & SLOT_USED));
  224.     m_pSlotData[nSlot].dwFlags |= SLOT_USED;
  225.     // update m_nRover (likely place to find a free slot is next one)
  226.     m_nRover = nSlot+1;
  227.  
  228.     LeaveCriticalSection(&m_sect);
  229.     return nSlot;   // slot can be used for FreeSlot, GetValue, SetValue
  230. }
  231.  
  232. void CThreadSlotData::FreeSlot(int nSlot)
  233. {
  234.     EnterCriticalSection(&m_sect);
  235.     ASSERT(nSlot != 0 && nSlot < m_nMax);
  236.     ASSERT(m_pSlotData != NULL);
  237.     ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
  238.  
  239.     // delete the data from all threads/processes
  240.     CThreadData* pData = m_list;
  241.     while (pData != NULL)
  242.     {
  243.         if (nSlot < pData->nCount)
  244.         {
  245.             delete (CNoTrackObject*)pData->pData[nSlot];
  246.             pData->pData[nSlot] = NULL;
  247.         }
  248.         pData = pData->pNext;
  249.     }
  250.     // free the slot itself
  251.     m_pSlotData[nSlot].dwFlags &= ~SLOT_USED;
  252.     LeaveCriticalSection(&m_sect);
  253. }
  254.  
  255. // special version of CThreadSlotData::GetData that only works with
  256. // thread local storage (and not process local storage)
  257. // this version is inlined and simplified for speed
  258. inline void* CThreadSlotData::GetThreadValue(int nSlot)
  259. {
  260.     ASSERT(nSlot != 0 && nSlot < m_nMax);
  261.     ASSERT(m_pSlotData != NULL);
  262.     ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
  263.     ASSERT(m_tlsIndex != (DWORD)-1);
  264.  
  265.     CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
  266.     if (pData == NULL || nSlot >= pData->nCount)
  267.         return NULL;
  268.     return pData->pData[nSlot];
  269. }
  270.  
  271. void CThreadSlotData::SetValue(int nSlot, void* pValue)
  272. {
  273.     ASSERT(nSlot != 0 && nSlot < m_nMax);
  274.     ASSERT(m_pSlotData != NULL);
  275.     ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
  276.  
  277.     CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
  278.     if (pData == NULL || nSlot >= pData->nCount && pValue != NULL)
  279.     {
  280.         // if pData is NULL then this thread has not been visited yet
  281.         if (pData == NULL)
  282.         {
  283.             pData = new CThreadData;
  284.             pData->nCount = 0;
  285.             pData->pData = NULL;
  286.             DEBUG_ONLY(pData->pNext = NULL);
  287.  
  288.             // protect while adding to global list
  289.             EnterCriticalSection(&m_sect);
  290.             m_list.AddHead(pData);
  291.             LeaveCriticalSection(&m_sect);
  292.         }
  293.  
  294.         // grow to now current size
  295.         if (pData->pData == NULL)
  296.             pData->pData = (void**)LocalAlloc(LMEM_FIXED, m_nMax*sizeof(LPVOID));
  297.         else
  298.             pData->pData = (void**)LocalReAlloc(pData->pData, m_nMax*sizeof(LPVOID),
  299.                 LMEM_MOVEABLE);
  300.         if (pData->pData == NULL)
  301.             AfxThrowMemoryException();
  302.  
  303.         // initialize the newly allocated part
  304.         memset(pData->pData + pData->nCount, 0,
  305.             (m_nMax - pData->nCount) * sizeof(LPVOID));
  306.         pData->nCount = m_nMax;
  307.         TlsSetValue(m_tlsIndex, pData);
  308.     }
  309.     ASSERT(pData->pData != NULL && nSlot < pData->nCount);
  310.     pData->pData[nSlot] = pValue;
  311. }
  312.  
  313. void CThreadSlotData::AssignInstance(HINSTANCE hInst)
  314. {
  315.     EnterCriticalSection(&m_sect);
  316.     ASSERT(m_pSlotData != NULL);
  317.     ASSERT(hInst != NULL);
  318.  
  319.     for (int i = 1; i < m_nMax; i++)
  320.     {
  321.         if (m_pSlotData[i].hInst == NULL && (m_pSlotData[i].dwFlags & SLOT_USED))
  322.             m_pSlotData[i].hInst = hInst;
  323.     }
  324.     LeaveCriticalSection(&m_sect);
  325. }
  326.  
  327. void CThreadSlotData::DeleteValues(CThreadData* pData, HINSTANCE hInst)
  328. {
  329.     // Note: does not lock critical section because only meant to be called
  330.     // from DeleteValues(HINSTANCE, BOOL).
  331.  
  332.     ASSERT(pData != NULL);
  333.  
  334.     // free each element in the table
  335.     BOOL bDelete = TRUE;
  336.     for (int i = 1; i < pData->nCount; i++)
  337.     {
  338.         if (hInst == NULL || m_pSlotData[i].hInst == hInst)
  339.         {
  340.             // delete the data since hInst matches (or is NULL)
  341.             delete (CNoTrackObject*)pData->pData[i];
  342.             pData->pData[i] = NULL;
  343.         }
  344.         else if (pData->pData[i] != NULL)
  345.         {
  346.             // don't delete thread data if other modules still alive
  347.             bDelete = FALSE;
  348.         }
  349.     }
  350.  
  351.     if (bDelete)
  352.     {
  353.         // remove from master list and free it
  354.         EnterCriticalSection(&m_sect);
  355.         m_list.Remove(pData);
  356.         LeaveCriticalSection(&m_sect);
  357.         LocalFree(pData->pData);
  358.         delete pData;
  359.  
  360.         // clear TLS index to prevent from re-use
  361.         TlsSetValue(m_tlsIndex, NULL);
  362.     }
  363. }
  364.  
  365. void CThreadSlotData::DeleteValues(HINSTANCE hInst, BOOL bAll)
  366. {
  367.     EnterCriticalSection(&m_sect);
  368.     if (!bAll)
  369.     {
  370.         // delete the values only for the current thread
  371.         CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
  372.         if (pData != NULL)
  373.             DeleteValues(pData, hInst);
  374.     }
  375.     else
  376.     {
  377.         // delete the values for all threads
  378.         CThreadData* pData = m_list;
  379.         while (pData != NULL)
  380.         {
  381.             CThreadData* pDataNext = pData->pNext;
  382.             DeleteValues(pData, hInst);
  383.             pData = pDataNext;
  384.         }
  385.     }
  386.     LeaveCriticalSection(&m_sect);
  387. }
  388.  
  389. /////////////////////////////////////////////////////////////////////////////
  390. // CThreadLocalObject
  391.  
  392. CNoTrackObject* CThreadLocalObject::GetData(
  393.     CNoTrackObject* (AFXAPI* pfnCreateObject)())
  394. {
  395. #if defined(_WIN32_WCE)
  396. // WinCE: When pVB 2.0 apps are closed, we sometimes have a problem with MFC based ActiveX controls
  397.     if((m_nSlot == 0) || ((_afxThreadData != NULL) && (m_nSlot >= _afxThreadData->m_nMax)))
  398. #else // _WIN32_WCE
  399.     if (m_nSlot == 0)
  400. #endif // _WIN32_WCE
  401.     {
  402.         if (_afxThreadData == NULL)
  403.         {
  404.             _afxThreadData = new(__afxThreadData) CThreadSlotData;
  405.             ASSERT(_afxThreadData != NULL);
  406.         }
  407.         m_nSlot = _afxThreadData->AllocSlot();
  408.         ASSERT(m_nSlot != 0);
  409.     }
  410.     CNoTrackObject* pValue =
  411.         (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
  412.     if (pValue == NULL)
  413.     {
  414.         // allocate zero-init object
  415.         pValue = (*pfnCreateObject)();
  416.  
  417.         // set tls data to newly created object
  418.         _afxThreadData->SetValue(m_nSlot, pValue);
  419.         ASSERT(_afxThreadData->GetThreadValue(m_nSlot) == pValue);
  420.     }
  421.     return pValue;
  422. }
  423.  
  424. CNoTrackObject* CThreadLocalObject::GetDataNA()
  425. {
  426.     if (m_nSlot == 0 || _afxThreadData == NULL)
  427.         return NULL;
  428.  
  429.     CNoTrackObject* pValue =
  430.         (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
  431.     return pValue;
  432. }
  433.  
  434. CThreadLocalObject::~CThreadLocalObject()
  435. {
  436.     if (m_nSlot != 0 && _afxThreadData != NULL)
  437.         _afxThreadData->FreeSlot(m_nSlot);
  438.     m_nSlot = 0;
  439. }
  440.  
  441. /////////////////////////////////////////////////////////////////////////////
  442. // CProcessLocalData
  443.  
  444. CNoTrackObject* CProcessLocalObject::GetData(
  445.     CNoTrackObject* (AFXAPI* pfnCreateObject)())
  446. {
  447.     if (m_pObject == NULL)
  448.     {
  449.         AfxLockGlobals(CRIT_PROCESSLOCAL);
  450.         TRY
  451.         {
  452.             if (m_pObject == NULL)
  453.                 m_pObject = (*pfnCreateObject)();
  454.         }
  455.         CATCH_ALL(e)
  456.         {
  457.             AfxUnlockGlobals(CRIT_PROCESSLOCAL);
  458.             THROW_LAST();
  459.         }
  460.         END_CATCH_ALL
  461.         AfxUnlockGlobals(CRIT_PROCESSLOCAL);
  462.     }
  463.     return m_pObject;
  464. }
  465.  
  466. CProcessLocalObject::~CProcessLocalObject()
  467. {
  468.     if (m_pObject != NULL)
  469.         delete m_pObject;
  470. }
  471.  
  472. /////////////////////////////////////////////////////////////////////////////
  473. // Init/Term for thread/process local data
  474.  
  475. void AFXAPI AfxInitLocalData(HINSTANCE hInst)
  476. {
  477.     if (_afxThreadData != NULL)
  478.         _afxThreadData->AssignInstance(hInst);
  479. }
  480.  
  481. void AFXAPI AfxTermLocalData(HINSTANCE hInst, BOOL bAll)
  482. {
  483.     if (_afxThreadData != NULL)
  484.         _afxThreadData->DeleteValues(hInst, bAll);
  485. }
  486.  
  487. // This reference count is needed to support Win32s, such that the
  488. // thread-local and process-local data is not destroyed prematurely.
  489. // It is basically a reference count of the number of processes that
  490. // have attached to the MFC DLL.
  491.  
  492. AFX_STATIC_DATA long _afxTlsRef = 0;
  493.  
  494. void AFXAPI AfxTlsAddRef()
  495. {
  496.     ++_afxTlsRef;
  497. }
  498.  
  499. void AFXAPI AfxTlsRelease()
  500. {
  501.     if (_afxTlsRef == 0 || --_afxTlsRef == 0)
  502.     {
  503.         if (_afxThreadData != NULL)
  504.         {
  505.             _afxThreadData->~CThreadSlotData();
  506.             _afxThreadData = NULL;
  507.         }
  508.     }
  509. }
  510.  
  511. /////////////////////////////////////////////////////////////////////////////
  512.